💡 AI 인사이트

🤖 AI가 여기에 결과를 출력합니다...

댓글 커뮤니티

쿠팡이벤트

이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

검색

    로딩 중이에요... 🐣

    [코담] 웹개발·실전 프로젝트·AI까지, 파이썬·장고의 모든것을 담아낸 강의와 개발 노트

    26 DB성능 최적화 | ✅ 저자: 이유정(박사)

    데이터베이스 성능 최적화란? 데이터베이스가 더 빠르게, 효율적으로 작동하도록 돕는 방법들을 말합니다.
    즉, "필요한 데이터를 빠르게 찾고, 저장 공간도 아끼고, 시스템을 안정적으로 유지"하기 위한 다양한 기술입니다.

    DB성능종류:

    1. Query 최적화: 필요한 데이터만 정확히 뽑아야 속도가 빨라요
    2. 인덱싱: 자주 찾는 열에 책갈피를 달면 조회가 빨라져요
    3. 데이터 베이스 설계: 너무 잘게 쪼개거나 뭉치면 오히려 느려져요
    4. 파티셔닝: 테이블을 나누면 필요한 부분만 빨리 읽을 수 있어요
    5. 하드웨어 서버 최적화: 서버 성능도 중요하지만, 설계가 먼저예요

    1️⃣ Query 최적화

    • SELECT *처럼 모든 데이터를 가져오는 방식은 느릴 수 있어요.
    • 정확히 필요한 컬럼만 골라서 조회하는 것이 훨씬 빠릅니다.
    -- 나쁨 (느림)
    SELECT * FROM employees;
    
    -- 좋음 (빠름)
    SELECT name, salary FROM employees WHERE department = 'Sales';
    

    실습코드:

    import pandas as pd
    import sqlite3
    
    # 1. 예시용 데이터프레임 만들기 (employees 테이블처럼)
    data = {
        'id': [1, 2, 3, 4, 5],
        'name': ['Alice', 'Bob', 'Charlie', 'David', 'Eve'],
        'salary': [5000, 6000, 4500, 7000, 4000],
        'department': ['HR', 'Sales', 'HR', 'IT', 'Sales']
    }
    df = pd.DataFrame(data)
    
    # 2. 메모리 기반 SQLite DB에 저장
    conn = sqlite3.connect(":memory:")
    df.to_sql("employees", conn, index=False)
    
    # 3. 나쁨 (비효율적인 전체 조회)
    sql_all = """
    SELECT * FROM employees;
    """
    df_all = pd.read_sql(sql_all, conn)
    print(" 전체 조회 결과:")
    print(df_all)
    
    # 4. 좋음 (필요한 열만 조건 필터링)
    sql_filtered = """
    SELECT name, salary
    FROM employees
    WHERE department = 'Sales';
    """
    df_filtered = pd.read_sql(sql_filtered, conn)
    print("\n 필터링된 조회 결과 (Sales 부서):")
    print(df_filtered)
    
    conn.close()
    

    출력결과:

    전체 조회 결과:
       id     name  salary department
    0   1    Alice    5000         HR
    1   2      Bob    6000      Sales
    2   3  Charlie    4500         HR
    3   4    David    7000         IT
    4   5      Eve    4000      Sales
    
    필터링된 조회 결과 (Sales 부서):
        name  salary
    0    Bob    6000
    1    Eve    4000
    

    2️⃣ 인덱싱(Indexing) 인덱스는 책의 목차처럼, 데이터가 어디 있는지 빠르게 찾게 도와주는 구조입니다. 자주 검색하는 열(예: id, email, salary)에 인덱스를 걸면 조회 속도가 빨라집니다.

    CREATE INDEX idx_salary ON employees(salary);
    

    하지만 인덱스가 너무 많으면 저장 공간이 늘어나고, 데이터를 추가/수정할 때 속도가 느려질 수 있어요. 필요한 곳에만 인덱스를 추가하는 게 중요합니다.

    자주 사용되는 인덱스 종류 6가지 1. B-트리 인덱스 (B-Tree Index)

    • 가장 일반적인 인덱스
    • 값이 정렬된 상태로 저장되어 있어 범위 검색, 정렬, 비교 연산에 강함
    • 대부분의 DB에서 기본 인덱스 타입으로 사용됨 예: salary > 5000, name BETWEEN 'A' AND 'M'

    2. 해시 인덱스 (Hash Index)

    • 값을 해시 함수로 변환하여 저장
    • 정확히 일치하는 값을 빠르게 찾을 때 유리함 (= 조건)
    • 하지만 범위 검색에는 적합하지 않음 예: WHERE email = 'user@example.com'

    3. 비트맵 인덱스 (Bitmap Index)

    • 각 값마다 비트 벡터를 만들어 저장
    • 값의 종류가 적고 고정된 경우에 유리 (예: 성별, 국가코드)
    • 빠르게 조합 조건을 계산할 수 있음 예: WHERE gender = 'F' AND region = 'Asia'

    4. 전문 검색 인덱스 (Full-Text Index)

    • 문장이나 텍스트 데이터에 사용
    • 단어 기준으로 분해(indexing)해서 빠르게 검색 가능
    • LIKE '%word%'보다 훨씬 빠름 예: WHERE MATCH(content) AGAINST('database')

    5. 공간 인덱스 (Spatial Index)

    • 좌표나 지도 같은 공간 데이터를 인덱싱
    • GIS(지리 정보 시스템)에서 사용됨
    • 2D/3D 범위, 거리 기반 쿼리에 강함 예: WHERE ST_Distance(location, point) < 10

    6. 복합 인덱스 (Composite Index)

    • 여러 열을 조합해서 만든 인덱스
    • 특정 열 조합이 자주 함께 검색될 때 유리
    • 왼쪽부터 순서대로 인덱스가 적용됨 (Left-most prefix rule) 예: CREATE INDEX idx_user_email ON users(username, email);

    실습코드:

    import pandas as pd
    import sqlite3
    
    # 1. 예제 데이터프레임 생성
    df = pd.DataFrame({
        'id': [1, 2, 3, 4, 5],
        'name': ['Alice', 'Bob', 'Charlie', 'David', 'Eve'],
        'salary': [5000, 6000, 4500, 7000, 4000],
        'department': ['HR', 'Sales', 'HR', 'IT', 'Sales']
    })
    
    # -------------------------------
    # SQL 방식: 인덱스 생성
    # -------------------------------
    conn = sqlite3.connect(":memory:")  # 메모리 기반 임시 DB
    df.to_sql("employees", conn, index=False)
    
    # SQL에서 salary 열에 인덱스 생성
    sql_create_index = """
    CREATE INDEX idx_salary ON employees(salary);
    """
    conn.execute(sql_create_index)
    
    # 조건 검색 (인덱스가 사용될 수 있음)
    sql_query = """
    SELECT name, salary
    FROM employees
    WHERE salary > 5000;
    """
    df_sql_result = pd.read_sql(sql_query, conn)
    
    print(" SQL 인덱싱 + 조건 검색 결과:")
    print(df_sql_result)
    
    # -------------------------------
    # Pandas 방식: 인덱스 설정
    # -------------------------------
    
    # salary 열을 인덱스로 설정
    df_pandas_indexed = df.set_index('salary')
    
    # 조건 필터링 (salary > 5000)
    df_pandas_filtered = df[df['salary'] > 5000][['name', 'salary']]
    
    print("\n Pandas 조건 검색 결과:")
    print(df_pandas_filtered)
    
    conn.close()
    

    출력결과:

    SQL 인덱싱 + 조건 검색 결과:
        name  salary
    0    Bob    6000
    1  David    7000
    
    Pandas 조건 검색 결과:
        name  salary
    1    Bob    6000
    3  David    7000
    

    3️⃣ 데이터베이스 설계 - 데이터를 어떻게 나눠서 저장하느냐(= 설계)가 성능에 큰 영향을 줍니다. - 너무 잘게 나누면 느려지고, 너무 뭉치면 관리가 어렵습니다. - 정규화(중복 제거)와 비정규화(속도 개선) 사이에서 균형이 중요합니다.


    4️⃣ 파티셔닝(Partitioning) - 파티셔닝은 큰 테이블을 여러 개로 나누는 기술입니다. - 예를 들어, sales 테이블을 연도(year) 기준으로 나누면,
    특정 연도만 검색할 때 더 빠르게 찾을 수 있습니다.

    CREATE TABLE sales
    PARTITION BY RANGE (year) (
      PARTITION p2022 VALUES LESS THAN (2023),
      PARTITION p2023 VALUES LESS THAN (2024)
    );
    

    SQL과 Pandas에서 연도(year) 기준으로 데이터를 나누어
    특정 연도에 해당하는 데이터만 빠르게 조회하는 구조를 비교해보기:

    import pandas as pd
    import sqlite3
    
    # 1. 예제 DataFrame 생성 (sales 데이터)
    df = pd.DataFrame({
        'id': [1, 2, 3, 4, 5, 6],
        'year': [2022, 2022, 2023, 2023, 2024, 2024],
        'amount': [100, 150, 200, 250, 300, 350]
    })
    
    # 2. SQLite 메모리 DB 생성 및 테이블 저장
    conn = sqlite3.connect(":memory:")
    df.to_sql("sales", conn, index=False)
    
    # 3. SQL로 특정 연도만 조회 (2023년 데이터)
    sql_query = """
    SELECT *
    FROM sales
    WHERE year = 2023;
    """
    
    df_sql_result = pd.read_sql(sql_query, conn)
    print(" SQL 방식 - 특정 연도 필터링 결과 (2023년):")
    print(df_sql_result)
    

    Pandas방식

    # 4. Pandas에서 연도 기준으로 분리
    df_2022 = df[df['year'] == 2022]
    df_2023 = df[df['year'] == 2023]
    df_2024 = df[df['year'] == 2024]
    
    print("\n Pandas 방식 - 2023년 데이터:")
    print(df_2023)
    
    # 5. 연도별 데이터프레임을 파티션처럼 저장
    partitions = {year: df[df['year'] == year] for year in df['year'].unique()}
    
    # 2023년 파티션 조회
    print("\n Pandas 딕셔너리 방식 - 2023 파티션:")
    print(partitions[2023])
    

    5️⃣ 🖥 하드웨어 서버 최적화

    • 하드디스크 대신 SSD를 쓰거나, 메모리나 CPU를 늘리면 성능이 좋아질 수 있어요.
    • 하지만 하드웨어보다 먼저 쿼리와 설계 최적화가 우선입니다.
    TOP
    preload preload